﻿using GameProtocol.Protocol;
using Google.Protobuf;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace GameLogic
{
    public class UDPServer : NetServer
    {
        protected UdpClient m_UDPClient;
        public override void Init(int receivePort = 24567, int sendPort = 24568)
        {
            base.Init(receivePort, sendPort);
            m_UDPClient = new UdpClient(receivePort);
            m_IsActive = true;
            DoReceive();
        }
        public override void Disconnect()
        {
            base.Disconnect();
            m_IsActive = false;
            foreach (var i in m_ClientHandleMap)
            {
                i.Value.Close();
            }
            m_ClientHandleMap.Clear();
            m_UDPClient.Close();
        }
        public override void Clear()
        {
            base.Clear();
            m_UDPClient.Close();
        }

        private bool m_IsActive = false;
        protected async void DoReceive()
        {
            if (!m_IsActive)
                return;
            UdpReceiveResult res;
            try
            {
                 res = await m_UDPClient.ReceiveAsync();
            }catch
            (Exception ex)
            {
                return;
            }
            var endPoint = res.RemoteEndPoint;
            var ipStr = endPoint.Address.ToString();
            if (!m_ClientHandleMap.ContainsKey(ipStr))
            {
                RecvOriginData(endPoint, res.Buffer);
            }
            else
            {
                (m_ClientHandleMap[ipStr] as UDPClientHandle)?.Input(res.Buffer);
            }
            DoReceive();
        }
        public override void Send(GameProtocol.Protocol.CSMsgId id, IPEndPoint ep, byte[] data)
        {
            MessageContent content = new MessageContent();
            if (data != null)
                content.Data = ByteString.CopyFrom(data);

            content.MsgID = id;

            //var length = GlobalFunction.PlusLengthHeadToByteArray(m_SendDataBuffer, );
            var sendData = content.ToByteArray();
            Send(new IPEndPoint(IPAddress.Broadcast, m_SendPort), sendData, sendData.Length);
        }
        protected override void OnClientTimeout(ClientHandle clientHand)
        {
            base.OnClientTimeout(clientHand);
        }

        protected void RecvOriginData(IPEndPoint endPoint, byte[] data)
        {
            var ipStr = endPoint.Address.ToString();
            GameProtocol.Protocol.MessageContent messageContent = null;
            try
            {
                messageContent = GameProtocol.Protocol.MessageContent.Parser.ParseFrom(data);
            }
            catch (Exception ex)
            {
                UnityEngine.Debug.LogError("接收到"+ endPoint.Address.ToString()+ "无法解析的奇怪原始数据：" + BitConverter.ToString(data) + "\n exception：" + ex.ToString());
            }
            if (messageContent != null && messageContent.MsgID == CSMsgId.ConnectRqr)
            {
                var rqrData = ConnectRqrData.Parser.ParseFrom(messageContent.Data);
                if (rqrData != null)
                {

                    var rspData = new ConnectRspData();
                    rspData.ConversationID = rqrData.ConversationID;
                    messageContent = new MessageContent();
                    messageContent.MsgID = CSMsgId.ConnectRsp;
                    messageContent.Data = ByteString.CopyFrom(rspData.ToByteArray());
                    var data2 = messageContent.ToByteArray();
                    Send(endPoint, data2, data2.Length);

                    var newClient = UDPClientHandle.Create(m_UDPClient, endPoint, rqrData.ConversationID);
                    newClient.HasHandShake = true;
                    newClient.IP = ipStr;
                    newClient.TimeoutCallback = OnClientTimeout;
                    newClient.ReceiveCallback = OnReceived;
                    m_ClientHandleMap.TryAdd(ipStr, newClient);

                }
            }
        }
        protected override void Send(IPEndPoint endPoint, byte[] date, int length)
        {
            if (endPoint.Address == IPAddress.Broadcast)
            {
                foreach (var i in m_ClientHandleMap)
                {
                    i.Value.Send(date, length);
                }
            }
            else
            {
                if (m_ClientHandleMap.TryGetValue(endPoint.Address.ToString(), out var kcp))
                {
                    kcp.Send(date, length);
                }
                else
                {
                    m_UDPClient.SendAsync(date, date.Length, endPoint);
                }
            }
        }

        protected override void OnReceived(IPEndPoint ep, byte[] data, int curOffset, int length)
        {
            var msg = MessageContent.Parser.ParseFrom(data, curOffset, length);
            if (msg != null && m_ReceiveEvents.ContainsKey(msg.MsgID))
            {
                var subData = msg.Data.ToByteArray();
                var rspData = ConnectRspData.Parser.ParseFrom(subData);
                m_ReceiveEvents[msg.MsgID].Invoke(ep, subData);
            }
        }
    }
}
